www.gusucode.com > VC++仿XP免费Prof UIS界面库-源码程序 > VC++仿XP免费Prof UIS界面库-源码程序/code/Src/ExtScrollWnd.cpp

    //Download by http://www.NewXing.com
// This is part of the Professional User Interface Suite library.
// Copyright (C) 2001-2004 FOSS Software, Inc.
// All rights reserved.
//
// http://www.prof-uis.com
// http://www.fossware.com
// mailto:foss@fossware.com
//
// This source code can be used, modified and redistributed
// under the terms of the license agreement that is included
// in the Professional User Interface Suite package.
//
// Warranties and Disclaimers:
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND
// INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
// IN NO EVENT WILL FOSS SOFTWARE INC. BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES,
// INCLUDING DAMAGES FOR LOSS OF PROFITS, LOSS OR INACCURACY OF DATA,
// INCURRED BY ANY PERSON FROM SUCH PERSON'S USAGE OF THIS SOFTWARE
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

#include "stdafx.h"

#if (!defined __EXT_MFC_NO_SCROLLWND)

#if (!defined __EXT_SCROLLWND_H)
	#include <ExtScrollWnd.h>
#endif 

#if (!defined __AFXPRIV_H__)
	#include <AfxPriv.h>
#endif 

#if (!defined __EXT_TOOLCONTROLBAR_H)
	#include <ExtToolControlBar.h>
#endif

#if (!defined __EXT_POPUP_MENU_WND_H)
	#include <ExtPopupMenuWnd.h>
#endif

#if (!defined __EXT_PAINT_MANAGER_H)
	#include <ExtPaintManager.h>
#endif

#if (!defined __EXT_MEMORY_DC_H)
	#include <../src/ExtMemoryDC.h>
#endif

#if _MFC_VER < 0x700
	#include <../src/AfxImpl.h>
#else
	#ifndef __AFXSTATE_H__
		#include <../src/mfc/afxstat_.h>
	#endif
	#include <../src/mfc/AfxImpl.h>
#endif

#if (!defined __EXT_LOCALIZATION_H)
	#include <../Src/ExtLocalization.h>
#endif

#include <../profuisdll/resource.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CExtScrollBar

IMPLEMENT_DYNCREATE( CExtScrollBar, CScrollBar );

CExtScrollBar::CExtScrollBar()
	: m_bAutoDeleteOnPostNcDestroy( false )
	, m_bReflectParentSizing( true )
	, m_eSO( CExtScrollBar::__ESO_AUTO )
	, m_bDisableAutoReserveSpace( false )
	, m_bAutoReserveSpaceBefore( false )
	, m_bAutoReserveSpaceAfter( false )
	, m_bSmoothPainting( true )
{
	_ScanSysMertics();
}

CExtScrollBar::~CExtScrollBar()
{
}

BEGIN_MESSAGE_MAP(CExtScrollBar, CScrollBar)
	//{{AFX_MSG_MAP(CExtScrollBar)
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
	__EXT_MFC_SAFE_ON_WM_SETTINGCHANGE()
	ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
END_MESSAGE_MAP()

void CExtScrollBar::_ScanSysMertics()
{
	ASSERT_VALID( this );
	m_nHorzBarHeight	= ::GetSystemMetrics( SM_CYHSCROLL );
	m_nVertBarWidth		= ::GetSystemMetrics( SM_CXVSCROLL );
}

void CExtScrollBar::SyncReservedSpace( CExtScrollBar * pOtherBar )
{
	ASSERT_VALID( this );
	ASSERT_VALID( pOtherBar );
	ASSERT( this != pOtherBar );
CWnd * pWndNext = GetWindow( GW_HWNDNEXT );
	if( pWndNext != pOtherBar )
		return;
	m_bAutoReserveSpaceBefore = m_bAutoReserveSpaceAfter = false;
	pOtherBar->m_bAutoReserveSpaceBefore = pOtherBar->m_bAutoReserveSpaceAfter = false;
	if( m_bDisableAutoReserveSpace )
		return;
	if( (GetStyle()&WS_VISIBLE) == 0 || (pOtherBar->GetStyle()&WS_VISIBLE) == 0 )
		return;
eScrollerOrientation_t _eSOown = GetScrollerOrientation();
eScrollerOrientation_t _eSOother = pOtherBar->GetScrollerOrientation();
	switch( _eSOown )
	{
	case __ESO_TOP:
	case __ESO_BOTTOM:
		switch( _eSOother )
		{
		case __ESO_LEFT:
			m_bAutoReserveSpaceBefore = true;
			break;
		case __ESO_RIGHT:
			m_bAutoReserveSpaceAfter = true;
			break;
		case __ESO_TOP:
		case __ESO_BOTTOM:
		case __ESO_NONE:
			return;
#ifdef _DEBUG
		default:
			ASSERT( FALSE );
			return;
#endif // _DEBUG
		} // switch( _eSOother )
		break;
	case __ESO_LEFT:
	case __ESO_RIGHT:
		switch( _eSOother )
		{
		case __ESO_TOP:
			m_bAutoReserveSpaceBefore = true;
			break;
		case __ESO_BOTTOM:
			m_bAutoReserveSpaceAfter = true;
			break;
		case __ESO_LEFT:
		case __ESO_RIGHT:
		case __ESO_NONE:
			return;
#ifdef _DEBUG
		default:
			ASSERT( FALSE );
			return;
#endif // _DEBUG
		} // switch( _eSOother )
		break;
	case __ESO_NONE:
		return;
#ifdef _DEBUG
	default:
		ASSERT( FALSE );
		return;
#endif // _DEBUG
	} // switch( _eSOown )
}

CExtScrollBar::eScrollerOrientation_t
	CExtScrollBar::GetScrollerOrientation() const
{
	ASSERT_VALID( this );
	ASSERT( __ESO_MIN_VALUE <= m_eSO && m_eSO <= __ESO_MAX_VALUE );
eScrollerOrientation_t _eSO = m_eSO;
	if( _eSO == __ESO_AUTO )
	{
		DWORD dwWndStyle = CWnd::GetStyle();
		if( ( dwWndStyle & (SBS_TOPALIGN|SBS_VERT) ) == (SBS_TOPALIGN) )
			_eSO = __ESO_TOP;
		else if( ( dwWndStyle & (SBS_BOTTOMALIGN|SBS_VERT) ) == (SBS_BOTTOMALIGN) )
			_eSO = __ESO_BOTTOM;
		else if( ( dwWndStyle & (SBS_LEFTALIGN|SBS_VERT) ) == (SBS_LEFTALIGN|SBS_VERT) )
			_eSO = __ESO_LEFT;
		else if( ( dwWndStyle & (SBS_RIGHTALIGN|SBS_VERT) ) == (SBS_RIGHTALIGN|SBS_VERT) )
			_eSO = __ESO_RIGHT;
		else
			_eSO = __ESO_NONE;
	} // if( _eSO == __ESO_AUTO )
	return _eSO;
}

void CExtScrollBar::PreSubclassWindow()
{
	CScrollBar::PreSubclassWindow();
	_ScanSysMertics();
}

void CExtScrollBar::PostNcDestroy()
{
	ASSERT_VALID( this );
	if( m_bAutoDeleteOnPostNcDestroy )
		delete this;
}

BOOL CExtScrollBar::OnEraseBkgnd(CDC* pDC) 
{
	if( !m_bSmoothPainting )
		return CScrollBar::OnEraseBkgnd( pDC );
	return TRUE;
}

void CExtScrollBar::OnPaint() 
{
	if( !m_bSmoothPainting )
	{
		CScrollBar::OnPaint();
		return;
	} // if( !m_bSmoothPainting )
CRect rcClient;
	GetClientRect( &rcClient );
CPaintDC dcPaint( this );
CExtMemoryDC dc( &dcPaint, &rcClient );
	DefWindowProc( WM_PAINT, (WPARAM)dc.GetSafeHdc(), 0L );
}

void CExtScrollBar::OnSettingChange(UINT uFlags, __EXT_MFC_SAFE_LPCTSTR lpszSection) 
{
	ASSERT_VALID( this );
	CScrollBar::OnSettingChange(uFlags, lpszSection);
	_ScanSysMertics();
}

LRESULT CExtScrollBar::OnSizeParent( WPARAM wParam, LPARAM lParam )
{
	ASSERT_VALID( this );
	if( !m_bReflectParentSizing )
		return (LRESULT)0;
	wParam;
DWORD dwWndStyle = CWnd::GetStyle();
	if( (dwWndStyle & WS_VISIBLE) == 0 )
		return 0;
AFX_SIZEPARENTPARAMS * lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
	ASSERT( lpLayout != NULL );

CRect rcOwnLayout( lpLayout->rect );
eScrollerOrientation_t _eSO = GetScrollerOrientation();
CSize _sizeNeeded( 0, 0 );
	switch( _eSO )
	{
	case __ESO_TOP:
		_sizeNeeded.cy = m_nHorzBarHeight;
		lpLayout->rect.top += _sizeNeeded.cy;
		rcOwnLayout.bottom = rcOwnLayout.top + _sizeNeeded.cy;
		lpLayout->sizeTotal.cy += _sizeNeeded.cy;
		if( m_bAutoReserveSpaceBefore )
			rcOwnLayout.left += m_nVertBarWidth;
		if( m_bAutoReserveSpaceAfter )
			rcOwnLayout.right -= m_nVertBarWidth;
		break;
	case __ESO_BOTTOM:
		_sizeNeeded.cy = m_nHorzBarHeight;
		lpLayout->rect.bottom -= _sizeNeeded.cy;
		rcOwnLayout.top = rcOwnLayout.bottom - _sizeNeeded.cy;
		lpLayout->sizeTotal.cy += _sizeNeeded.cy;
		if( m_bAutoReserveSpaceBefore )
			rcOwnLayout.left += m_nVertBarWidth;
		if( m_bAutoReserveSpaceAfter )
			rcOwnLayout.right -= m_nVertBarWidth;
		break;
	case __ESO_LEFT:
		_sizeNeeded.cx = m_nVertBarWidth;
		lpLayout->rect.left += _sizeNeeded.cx;
		rcOwnLayout.right = rcOwnLayout.left + _sizeNeeded.cx;
		lpLayout->sizeTotal.cx += _sizeNeeded.cx;
		if( m_bAutoReserveSpaceBefore )
			rcOwnLayout.top += m_nHorzBarHeight;
		if( m_bAutoReserveSpaceAfter )
			rcOwnLayout.bottom -= m_nHorzBarHeight;
		break;
	case __ESO_RIGHT:
		_sizeNeeded.cx = m_nVertBarWidth;
		lpLayout->rect.right -= _sizeNeeded.cx;
		rcOwnLayout.left = rcOwnLayout.right - _sizeNeeded.cx;
		lpLayout->sizeTotal.cx += _sizeNeeded.cx;
		if( m_bAutoReserveSpaceBefore )
			rcOwnLayout.top += m_nHorzBarHeight;
		if( m_bAutoReserveSpaceAfter )
			rcOwnLayout.bottom -= m_nHorzBarHeight;
		break;
	case __ESO_NONE:
		break;
#ifdef _DEBUG
	default:
		ASSERT( FALSE );
		break;
#endif // _DEBUG
	} // switch( _eSO )

//	ASSERT( ! rcOwnLayout.IsRectEmpty() );
	if( lpLayout->hDWP != NULL )
	{
		::AfxRepositionWindow(
			lpLayout,
			m_hWnd,
			&rcOwnLayout
			);
	} // if( lpLayout->hDWP != NULL )
	return 0L;
}

/////////////////////////////////////////////////////////////////////////////
// CExtScrollWnd

IMPLEMENT_DYNCREATE( CExtScrollWnd, CWnd );

CExtScrollWnd::CExtScrollWnd()
	: m_nUpdateScrollBars( 0 )
	, m_bScrollPhysical( false )
	, m_bEatErasing( true )
	, m_bBufferedPainting( true )
	, m_bScrollUpdateWindow( false )
	, m_bScrollInvalidate( true )
	, m_bScrollErase( false )
	, m_bRedrawUpdateWindow( false )
	, m_bRedrawInvalidate( true )
	, m_bRedrawErase( false )
	, m_bUse32BitScrollInfo( true )
{
}

CExtScrollWnd::~CExtScrollWnd()
{
}


BEGIN_MESSAGE_MAP(CExtScrollWnd, CWnd)
	//{{AFX_MSG_MAP(CExtScrollWnd)
	ON_WM_SIZE()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
	ON_WM_SYSCOLORCHANGE()
	__EXT_MFC_SAFE_ON_WM_SETTINGCHANGE()
	ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange)
	ON_MESSAGE(__ExtMfc_WM_THEMECHANGED, OnThemeChanged)
END_MESSAGE_MAP()

void CExtScrollWnd::OnSysColorChange() 
{
	ASSERT_VALID( this );
	CWnd::OnSysColorChange();
	g_PaintManager.OnSysColorChange( this );
	g_CmdManager.OnSysColorChange( this );
	Invalidate();
}

LRESULT CExtScrollWnd::OnDisplayChange( WPARAM wParam, LPARAM lParam )
{
LRESULT lResult = CWnd::OnDisplayChange( wParam, lParam );
	g_PaintManager.OnDisplayChange( this, (INT)wParam, CPoint(lParam) );
	g_CmdManager.OnDisplayChange( this, (INT)wParam, CPoint(lParam) );
	return lResult;
}

LRESULT CExtScrollWnd::OnThemeChanged( WPARAM wParam, LPARAM lParam )
{
LRESULT lResult = Default();
	g_PaintManager.OnThemeChanged( this, wParam, lParam );
	g_CmdManager.OnThemeChanged( this, wParam, lParam );
	OnSwRecalcLayout( true );
	return lResult;
}

void CExtScrollWnd::OnSettingChange(UINT uFlags, __EXT_MFC_SAFE_LPCTSTR lpszSection) 
{
	ASSERT_VALID( this );
	CWnd::OnSettingChange(uFlags, lpszSection);
	g_PaintManager.OnSettingChange( this, uFlags, lpszSection );
	g_CmdManager.OnSettingChange( this, uFlags, lpszSection );
	OnSwRecalcLayout( true );
}

CSize CExtScrollWnd::OnSwGetTotalSize() const
{
	ASSERT_VALID( this );
	return CSize( 0, 0 );
}

CSize CExtScrollWnd::OnSwGetPageSize( int nDirection ) const
{
	ASSERT_VALID( this );
	nDirection;
	return CSize( 0, 0 );
}

CSize CExtScrollWnd::OnSwGetLineSize( int nDirection ) const
{
	ASSERT_VALID( this );
	nDirection;
	return CSize( 0, 0 );
}

bool CExtScrollWnd::OnSwScrollInfoAdjust(
	int nBar,
	SCROLLINFO & si,
	bool bRedraw // = true
	)
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( nBar );
	if( pScrollBarWnd != NULL )
	{
		if( pScrollBarWnd->SetScrollInfo(
				&si,
				bRedraw ? TRUE : FALSE
				)
			)
			return true;
		return false;
	} // if( pScrollBarWnd != NULL )
	if( CWnd::SetScrollInfo(
			nBar,
			&si,
			bRedraw ? TRUE : FALSE
			)
		)
		return true;
	return false;
}

void CExtScrollWnd::OnSwSetScrollRange(
	int nBar,
	LONG nMinPos,
	LONG nMaxPos,
	bool bRedraw // = true
	)
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( nBar );
	if( pScrollBarWnd != NULL )
	{
		pScrollBarWnd->SetScrollRange(
			(int)nMinPos,
			(int)nMaxPos,
			bRedraw ? TRUE : FALSE
			);
		return;
	} // if( pScrollBarWnd != NULL )
	CWnd::SetScrollRange(
		nBar,
		(int)nMinPos,
		(int)nMaxPos,
		bRedraw ? TRUE : FALSE
		);
}

LONG CExtScrollWnd::ScrollLimit32Get( int nBar ) const
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( nBar );
	if( pScrollBarWnd != NULL )
	{
		if( m_bUse32BitScrollInfo )
		{
			SCROLLINFO _scroll_info;
			::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
			_scroll_info.cbSize = sizeof(SCROLLINFO);
			if(	pScrollBarWnd->GetScrollInfo(
					&_scroll_info,
					SIF_RANGE|SIF_PAGE
					)
				)
			{
				LONG nRetVal = (LONG)
					(_scroll_info.nMax
					- _scroll_info.nMin
					- _scroll_info.nPage
					+ 1);
				ASSERT( nRetVal >= 0 );
				return nRetVal;
			}
			//ASSERT( FALSE );
		} // if( m_bUse32BitScrollInfo )
		LONG nRetVal = (LONG)
			pScrollBarWnd->GetScrollLimit();
		return nRetVal;
	} // if( pScrollBarWnd != NULL )
	if( m_bUse32BitScrollInfo )
	{
		SCROLLINFO _scroll_info;
		::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
		_scroll_info.cbSize = sizeof(SCROLLINFO);
		if(	( const_cast < CExtScrollWnd * > ( this ) ) ->
				CWnd::GetScrollInfo(
					nBar,
					&_scroll_info,
					SIF_RANGE|SIF_PAGE
					)
			)
		{
			LONG nRetVal = (LONG)
				(_scroll_info.nMax
				- _scroll_info.nMin
				- _scroll_info.nPage
				+ 1);
			ASSERT( nRetVal >= 0 );
			return nRetVal;
		}
		//ASSERT( FALSE );
	} // if( m_bUse32BitScrollInfo )
LONG nRetVal = (LONG)
		(	( const_cast < CExtScrollWnd * > ( this ) ) ->
				CWnd::GetScrollLimit( nBar )
		);
	return nRetVal;
}

void CExtScrollWnd::ScrollInfo32Get(
	int nBar,
	LONG * p_nMinPos,
	LONG * p_nMaxPos,
	LONG * p_nPageSize,
	LONG * p_nCurrPos,
	LONG * p_nTrackPos
	) const
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
	if( p_nMinPos != NULL )
		*p_nMinPos = 0L;
	if( p_nMaxPos != NULL )
		*p_nMaxPos = 0L;
	if( p_nPageSize != NULL )
		*p_nPageSize = 0L;
	if( p_nCurrPos != NULL )
		*p_nCurrPos = 0L;
	if( p_nTrackPos != NULL )
		*p_nTrackPos = 0L;
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( nBar );
	if( pScrollBarWnd != NULL )
	{
		if( m_bUse32BitScrollInfo )
		{
			SCROLLINFO _scroll_info;
			::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
			_scroll_info.cbSize = sizeof(SCROLLINFO);
			if(	pScrollBarWnd->GetScrollInfo(
					&_scroll_info,
					SIF_RANGE|SIF_PAGE|SIF_POS|SIF_TRACKPOS
					)
				)
			{
				if( p_nMinPos != NULL )
					*p_nMinPos = _scroll_info.nMin;
				if( p_nMaxPos != NULL )
					*p_nMaxPos = _scroll_info.nMax;
				if( p_nPageSize != NULL )
					*p_nPageSize = _scroll_info.nPage;
				if( p_nCurrPos != NULL )
					*p_nCurrPos = _scroll_info.nPos;
				if( p_nTrackPos != NULL )
					*p_nTrackPos = _scroll_info.nTrackPos;
				return;
			}
			//ASSERT( FALSE );
		} // if( m_bUse32BitScrollInfo )
		if( p_nMinPos != NULL || p_nMaxPos != NULL )
		{
			INT nMin = 0, nMax = 0;
			pScrollBarWnd->GetScrollRange( &nMin, &nMax );
			if( p_nMinPos != NULL )
				*p_nMinPos = nMin;
			if( p_nMaxPos != NULL )
				*p_nMaxPos = nMax;
			
		} // if( p_nMinPos != NULL || p_nMaxPos != NULL )
		if( p_nCurrPos != NULL || p_nTrackPos != NULL )
		{
			INT nPos = pScrollBarWnd->GetScrollPos();
			if( p_nCurrPos != NULL )
				*p_nCurrPos = nPos;
			if( p_nTrackPos != NULL )
				*p_nTrackPos = nPos;
		} // if( p_nCurrPos != NULL || p_nTrackPos != NULL )
		return;
	} // if( pScrollBarWnd != NULL )
	if( m_bUse32BitScrollInfo )
	{
		SCROLLINFO _scroll_info;
		::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
		_scroll_info.cbSize = sizeof(SCROLLINFO);
		if(	( const_cast < CExtScrollWnd * > ( this ) ) ->
				CWnd::GetScrollInfo(
					nBar,
					&_scroll_info,
					SIF_RANGE|SIF_PAGE|SIF_POS|SIF_TRACKPOS
					)
			)
		{
			if( p_nMinPos != NULL )
				*p_nMinPos = _scroll_info.nMin;
			if( p_nMaxPos != NULL )
				*p_nMaxPos = _scroll_info.nMax;
			if( p_nPageSize != NULL )
				*p_nPageSize = _scroll_info.nPage;
			if( p_nCurrPos != NULL )
				*p_nCurrPos = _scroll_info.nPos;
			if( p_nTrackPos != NULL )
				*p_nTrackPos = _scroll_info.nTrackPos;
			return;
		}
		//ASSERT( FALSE );
	} // if( m_bUse32BitScrollInfo )
	if( p_nMinPos != NULL || p_nMaxPos != NULL )
	{
		INT nMin = 0, nMax = 0;
		CWnd::GetScrollRange( nBar, &nMin, &nMax );
		if( p_nMinPos != NULL )
			*p_nMinPos = nMin;
		if( p_nMaxPos != NULL )
			*p_nMaxPos = nMax;
		
	} // if( p_nMinPos != NULL || p_nMaxPos != NULL )
	if( p_nCurrPos != NULL || p_nTrackPos != NULL )
	{
		INT nPos = CWnd::GetScrollPos( nBar );
		if( p_nCurrPos != NULL )
			*p_nCurrPos = nPos;
		if( p_nTrackPos != NULL )
			*p_nTrackPos = nPos;
	} // if( p_nCurrPos != NULL || p_nTrackPos != NULL )
	return;
}

LONG CExtScrollWnd::ScrollPos32Get(
	int nBar,
	bool bTrackPos // = false
	) const
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( nBar );
	if( pScrollBarWnd != NULL )
	{
		if( m_bUse32BitScrollInfo )
		{
			SCROLLINFO _scroll_info;
			::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
			_scroll_info.cbSize = sizeof(SCROLLINFO);
			if(	pScrollBarWnd->GetScrollInfo(
					&_scroll_info,
					bTrackPos ? SIF_TRACKPOS : SIF_POS
					)
				)
			{
				LONG nRetVal = (LONG)
					(	bTrackPos
							? _scroll_info.nTrackPos
							: _scroll_info.nPos
					);
				return nRetVal;
			}
			//ASSERT( FALSE );
		} // if( m_bUse32BitScrollInfo )
		LONG nRetVal = (LONG)
			pScrollBarWnd->GetScrollPos();
		return nRetVal;
	} // if( pScrollBarWnd != NULL )
DWORD dwWndStyle = CWnd::GetStyle();
	if(		( nBar == SB_HORZ && (dwWndStyle & WS_HSCROLL) == 0 )
		||	( nBar == SB_VERT && (dwWndStyle & WS_VSCROLL) == 0 )
		)
		return 0;
	if( m_bUse32BitScrollInfo )
	{
		SCROLLINFO _scroll_info;
		::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
		_scroll_info.cbSize = sizeof(SCROLLINFO);
		if( ( const_cast < CExtScrollWnd * > ( this ) ) ->
				CWnd::GetScrollInfo(
					nBar,
					&_scroll_info,
					bTrackPos ? SIF_TRACKPOS : SIF_POS
					)
				)
		{
			LONG nRetVal = (LONG)
				(	bTrackPos
						? _scroll_info.nTrackPos
						: _scroll_info.nPos
				);
			return nRetVal;
		}
		//ASSERT( FALSE );
	} // if( m_bUse32BitScrollInfo )
LONG nRetVal = (LONG)
		(	( const_cast < CExtScrollWnd * > ( this ) ) ->
				CWnd::GetScrollPos( nBar )
		);
	return nRetVal;
}

void CExtScrollWnd::ScrollPos32Set(
	int nBar,
	LONG nPos,
	bool bRedraw // = true
	)
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( nBar );
	if( pScrollBarWnd != NULL )
	{
		if( m_bUse32BitScrollInfo )
		{
			SCROLLINFO _scroll_info;
			::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
			_scroll_info.cbSize = sizeof(SCROLLINFO);
			_scroll_info.fMask = SIF_POS;
			_scroll_info.nPos = (int)nPos;
			if( pScrollBarWnd->SetScrollInfo(
					&_scroll_info,
					bRedraw ? TRUE : FALSE
					)
				)
				return;
			//ASSERT( FALSE );
		} // if( m_bUse32BitScrollInfo )
		pScrollBarWnd->SetScrollPos(
			(int)nPos,
			bRedraw ? TRUE : FALSE
			);
		return;
	} // if( pScrollBarWnd != NULL )
	if( m_bUse32BitScrollInfo )
	{
		SCROLLINFO _scroll_info;
		::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
		_scroll_info.cbSize = sizeof(SCROLLINFO);
		_scroll_info.fMask = SIF_POS;
		_scroll_info.nPos = (int)nPos;
		if( CWnd::SetScrollInfo(
				nBar,
				&_scroll_info,
				bRedraw ? TRUE : FALSE
				)
			)
			return;
		//ASSERT( FALSE );
	} // if( m_bUse32BitScrollInfo )
	CWnd::SetScrollPos(
		nBar,
		(int)nPos,
		bRedraw ? TRUE : FALSE
		);
}

CPoint CExtScrollWnd::OnSwGetScrollPos() const
{
	ASSERT_VALID( this );
CPoint pt(
		ScrollPos32Get( SB_HORZ ),
		ScrollPos32Get( SB_VERT )
		);
	ASSERT( pt.x >= 0 && pt.y >= 0 );
	return pt;
}

CPoint CExtScrollWnd::OnSwGetScrollPaintPos() const
{
	ASSERT_VALID( this );
	return OnSwGetScrollPos();
}

CRect CExtScrollWnd::OnSwRecalcLayout(
	bool bDoLayout,
	LPCRECT pRectClientSrc // = NULL
	)
{
	ASSERT_VALID( this );
	if( bDoLayout )
	{
		CScrollBar * pScrollBarWndH = GetScrollBarCtrl( SB_HORZ );
		CScrollBar * pScrollBarWndV = GetScrollBarCtrl( SB_VERT );
		if( pScrollBarWndH != NULL && pScrollBarWndV != NULL )
		{
			CExtScrollBar * pExtScrollBarWndH = DYNAMIC_DOWNCAST( CExtScrollBar, pScrollBarWndH );
			CExtScrollBar * pExtScrollBarWndV = DYNAMIC_DOWNCAST( CExtScrollBar, pScrollBarWndV );
			if( pExtScrollBarWndH != NULL && pExtScrollBarWndV != NULL )
			{
				pExtScrollBarWndH->SyncReservedSpace( pExtScrollBarWndV );
				pExtScrollBarWndV->SyncReservedSpace( pExtScrollBarWndH );
			} // if( pExtScrollBarWndH != NULL && pExtScrollBarWndV != NULL )
		} // if( pScrollBarWndH != NULL && pScrollBarWndV != NULL )
	} // if( bDoLayout )
CRect rcClient;
	if( pRectClientSrc != NULL )
		rcClient = *pRectClientSrc;
	else
		CWnd::GetClientRect( &rcClient );
	CWnd::RepositionBars(
		0,
		0x0FFFF,
		AFX_IDW_PANE_FIRST,
		bDoLayout ? CWnd::reposDefault : CWnd::reposQuery,
		&rcClient,
		&rcClient,
		TRUE
		);
	return rcClient;
}

CRect CExtScrollWnd::OnSwGetClientRect() const
{
	ASSERT_VALID( this );
CRect rcClient =
		( const_cast < CExtScrollWnd * > ( this ) )
			-> OnSwRecalcLayout( false );
	return rcClient;
}

bool CExtScrollWnd::OnSwHasScrollBar( bool bHorz ) const
{
	ASSERT_VALID( this );
CScrollBar * pScrollBarWnd = GetScrollBarCtrl( bHorz ? SB_HORZ : SB_VERT );
	if( pScrollBarWnd != NULL )
	{
		if( pScrollBarWnd->IsWindowEnabled() )
			return true;
		return false;
	} // if( pScrollBarWnd != NULL )
DWORD dwWndStyle = CWnd::GetStyle();
DWORD dwTestStyle = bHorz ? WS_HSCROLL : WS_VSCROLL;
	if( ( dwWndStyle & dwTestStyle ) != 0 )
		return true;
	return false;
}

bool CExtScrollWnd::OnSwCanAutoHideScrollBar( bool bHorz ) const
{
	ASSERT_VALID( this );
	bHorz;
	return true;
}

void CExtScrollWnd::OnSwEnableScrollBarCtrl( int nBar, bool bEnable )
{
	ASSERT_VALID( this );
	ASSERT( nBar == SB_HORZ || nBar == SB_VERT || nBar == SB_BOTH );
DWORD dwWndStyle = CWnd::GetStyle();
CPoint ptMove = OnSwGetScrollPos();
CScrollBar * pScrollBarWndH = GetScrollBarCtrl( SB_HORZ );
CScrollBar * pScrollBarWndV = GetScrollBarCtrl( SB_VERT );
	if( nBar == SB_HORZ || nBar == SB_BOTH )
	{
		if( (!bEnable) && ptMove.x != 0 )
		{
			ptMove.x = 0;
			OnSwSetScrollPos( ptMove );
		} // if( (!bEnable) && ptMove.x != 0 )
		if( pScrollBarWndH != NULL )
		{
			if( (dwWndStyle & WS_HSCROLL) != 0 )
				CWnd::ShowScrollBar( SB_HORZ, FALSE );
			bool bAreadyEnabled = pScrollBarWndH->IsWindowEnabled() ? true : false;
			if(	!(		( bAreadyEnabled && bEnable )
					||	( (!bAreadyEnabled) && (!bEnable) )
					)
				)
			{
				pScrollBarWndH->EnableWindow( bEnable ? TRUE : FALSE );
				if( OnSwCanAutoHideScrollBar(true) )
					pScrollBarWndH->ShowWindow( bEnable ? SW_SHOW : SW_HIDE );
				else if( bEnable && (pScrollBarWndH->GetStyle()&WS_VISIBLE) == 0 )
					pScrollBarWndH->ShowWindow( SW_SHOW );
			}
		} // if( pScrollBarWndH != NULL )
		else
		{
			if( OnSwCanAutoHideScrollBar(true) )
				CWnd::ShowScrollBar(
					SB_HORZ,
					bEnable ? TRUE : FALSE
					);
			else
				CWnd::EnableScrollBar(
					SB_HORZ,
					bEnable ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH
					);
		} // else from if( pScrollBarWndH != NULL )
	} // if( nBar == SB_HORZ || nBar == SB_BOTH )
	if( nBar == SB_VERT || nBar == SB_BOTH )
	{
		if( (!bEnable) && ptMove.y != 0 )
		{
			ptMove.y = 0;
			OnSwSetScrollPos( ptMove );
		} // if( (!bEnable) && ptMove.y != 0 )
		if( pScrollBarWndV != NULL )
		{
			if( (dwWndStyle & WS_VSCROLL) != 0 )
				CWnd::ShowScrollBar( SB_VERT, FALSE );
			bool bAreadyEnabled = pScrollBarWndV->IsWindowEnabled() ? true : false;
			if(	!(		( bAreadyEnabled && bEnable )
					||	( (!bAreadyEnabled) && (!bEnable) )
					)
				)
			{
				pScrollBarWndV->EnableWindow( bEnable ? TRUE : FALSE );
				if( OnSwCanAutoHideScrollBar(false) )
					pScrollBarWndV->ShowWindow( bEnable ? SW_SHOW : SW_HIDE );
				else if( bEnable && (pScrollBarWndV->GetStyle()&WS_VISIBLE) == 0 )
					pScrollBarWndV->ShowWindow( SW_SHOW );
			}
		} // if( pScrollBarWndV != NULL )
		else
		{
			if( OnSwCanAutoHideScrollBar(false) )
				CWnd::ShowScrollBar(
					SB_VERT,
					bEnable ? TRUE : FALSE
					);
			else
				CWnd::EnableScrollBar(
					SB_VERT,
					bEnable ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH
					);
		} // else from if( pScrollBarWndV != NULL )
	} // if( nBar == SB_VERT || nBar == SB_BOTH )
CExtScrollBar * pExtScrollBarWndH = DYNAMIC_DOWNCAST( CExtScrollBar, pScrollBarWndH );
CExtScrollBar * pExtScrollBarWndV = DYNAMIC_DOWNCAST( CExtScrollBar, pScrollBarWndV );
	if( pExtScrollBarWndH != NULL && pExtScrollBarWndV != NULL )
	{
		pExtScrollBarWndH->SyncReservedSpace( pExtScrollBarWndV );
		pExtScrollBarWndV->SyncReservedSpace( pExtScrollBarWndH );
	} // if( pExtScrollBarWndH != NULL && pExtScrollBarWndV != NULL )
}

void CExtScrollWnd::OnSwSetScrollPos( POINT pt )
{
	ASSERT_VALID( this );
	ASSERT( pt.x >= 0 && pt.y >= 0 );
int xOrgValue = ScrollPos32Get( SB_HORZ );
	ScrollPos32Set( SB_HORZ, pt.x );
int yOrgValue = ScrollPos32Get( SB_VERT );
	ScrollPos32Set( SB_VERT, pt.y );
	OnSwDoScrollWindow(
		xOrgValue - pt.x,
		yOrgValue - pt.y
		);
}

UINT CExtScrollWnd::OnSwCalcMouseScrollLines(
	UINT fFlags,
	short zDelta,
	CPoint point
	)
{
	ASSERT_VALID( this );
	fFlags;
	zDelta;
	point;
	return g_PaintManager.GetMouseWheelScrollLines();
}

bool CExtScrollWnd::OnSwDoMouseWheel(
	UINT fFlags,
	short zDelta,
	CPoint point
	)
{
	ASSERT_VALID( this );
	point;
	if(		(fFlags&(MK_CONTROL)) != 0
		||	CExtToolControlBar::g_bMenuTracking
		||	CExtPopupMenuWnd::IsMenuTracking()
		)
		return false;

	if( ! ( OnSwHasScrollBar(true) || OnSwHasScrollBar(false) ) )
		return false;
bool bResult = false;
UINT uWheelScrollLines =
		OnSwCalcMouseScrollLines(
			fFlags,
			zDelta,
			point
			);
	if(		OnSwHasScrollBar(false)
		&&	( (fFlags&(MK_SHIFT)) == 0 )
		)
	{
		int nDisplacement;
		int nToScroll =
			::MulDiv( -zDelta, uWheelScrollLines, WHEEL_DELTA );
		if(		nToScroll == -1
			||	uWheelScrollLines == WHEEL_PAGESCROLL
			)
		{
			nDisplacement = OnSwGetPageSize( -1 ).cy;
			if( zDelta > 0 )
				nDisplacement = -nDisplacement;
		}
		else
		{
			nDisplacement =
				nToScroll * OnSwGetLineSize( 1 ).cy;
			nDisplacement =
				min(
					nDisplacement,
					OnSwGetPageSize( 1 ).cy
					);
		}
		bResult =
			OnSwDoScrollBy(
				CSize( 0, nDisplacement ),
				true
				);
	}
	else if(
			OnSwHasScrollBar( true )
		&&	( (fFlags&(MK_SHIFT)) != 0 )
		)
	{
		int nDisplacement;
		int nToScroll =
			::MulDiv( -zDelta, uWheelScrollLines, WHEEL_DELTA );
		if(		nToScroll == -1
			||	uWheelScrollLines == WHEEL_PAGESCROLL
			)
		{
			nDisplacement = OnSwGetPageSize( -1 ).cx;
			if( zDelta > 0 )
				nDisplacement = -nDisplacement;
		}
		else
		{
			nDisplacement =
				nToScroll * OnSwGetLineSize( 1 ).cx;
			nDisplacement =
				min(
					nDisplacement,
					OnSwGetPageSize( 1 ).cx
					);
		}
		bResult =
			OnSwDoScrollBy(
				CSize( nDisplacement, 0 ),
				true
				);
	}

	if( bResult )
	{
		OnSwInvalidate( m_bScrollErase );
		if( m_bScrollUpdateWindow )
			CWnd::UpdateWindow();
	}

	return bResult;
}

bool CExtScrollWnd::OnSwDoScroll(
	UINT nScrollCode,
	UINT nPos,
	bool bDoScroll // = true
	)
{
	ASSERT_VALID( this );
LONG xPos, xOrgValue, yPos, yOrgValue;
	xOrgValue = xPos = ScrollPos32Get( SB_HORZ );
	switch( LOBYTE(nScrollCode) )
	{
	case SB_TOP:		xPos  = 0;							break;
	case SB_BOTTOM:		xPos  = __EXT_SCROLL_NUMERIC_MAX;	break;
	case SB_LINEUP:		xPos -= OnSwGetLineSize( -1 ).cx;	break;
	case SB_LINEDOWN:	xPos += OnSwGetLineSize(  1 ).cx;	break;
	case SB_PAGEUP:		xPos -= OnSwGetPageSize( -1 ).cx;	break;
	case SB_PAGEDOWN:	xPos += OnSwGetPageSize(  1 ).cx;	break;
	case SB_THUMBTRACK:
		if( ! OnSwQueryThumbTrackEnabled(true) )
			break;
	case SB_THUMBPOSITION:
			if( m_bUse32BitScrollInfo )
				nPos = ScrollPos32Get( SB_HORZ, true );
			xPos  = nPos;
		break;
	}
	yOrgValue = yPos = ScrollPos32Get( SB_VERT );
	switch( HIBYTE(nScrollCode) )
	{
	case SB_TOP:		yPos  = 0;							break;
	case SB_BOTTOM:		yPos  = __EXT_SCROLL_NUMERIC_MAX;	break;
	case SB_LINEUP:		yPos -= OnSwGetLineSize( -1 ).cy;	break;
	case SB_LINEDOWN:	yPos += OnSwGetLineSize(  1 ).cy;	break;
	case SB_PAGEUP:		yPos -= OnSwGetPageSize( -1 ).cy;	break;
	case SB_PAGEDOWN:	yPos += OnSwGetPageSize(  1 ).cy;	break;
	case SB_THUMBTRACK:
		if( ! OnSwQueryThumbTrackEnabled(false) )
			break;
	case SB_THUMBPOSITION:
			if( m_bUse32BitScrollInfo )
				nPos = ScrollPos32Get( SB_VERT, true );
			yPos  = nPos;
		break;
	}
bool bResult =
		OnSwDoScrollBy(
			CSize( xPos - xOrgValue, yPos - yOrgValue ),
			bDoScroll
			);
	if( bResult && bDoScroll && m_bScrollUpdateWindow )
		CWnd::UpdateWindow();
	return bResult;
}

bool CExtScrollWnd::OnSwDoScrollBy(
	CSize sizeScroll,
	bool bDoScroll // = true
	)
{
	ASSERT_VALID( this );
int xMaxValue, xOrgValue, xPos, yMaxValue, yOrgValue, yPos;
	if( ! OnSwHasScrollBar(false) )
		sizeScroll.cy = 0;
	if( ! OnSwHasScrollBar(true) )
		sizeScroll.cx = 0;
	// adjust current positions
	xOrgValue = xPos = ScrollPos32Get( SB_HORZ );
	xMaxValue = ScrollLimit32Get( SB_HORZ );
	xPos += sizeScroll.cx;
	if( xPos < 0 )
		xPos = 0;
	else if( xPos > xMaxValue )
		xPos = xMaxValue;
	yOrgValue = yPos = ScrollPos32Get( SB_VERT );
	yMaxValue = ScrollLimit32Get( SB_VERT );
	yPos += sizeScroll.cy;
	if( yPos < 0 )
		yPos = 0;
	else if( yPos > yMaxValue )
		yPos = yMaxValue;
	if( xPos == xOrgValue && yPos == yOrgValue )
		return false;
	if( bDoScroll )
	{
		OnSwDoScrollWindow(
			xOrgValue - xPos,
			yOrgValue - yPos
			);
		if( xPos != xOrgValue )
			ScrollPos32Set( SB_HORZ, xPos );
		if( yPos != yOrgValue )
			ScrollPos32Set( SB_VERT, yPos );
	}
	return true;
}

CSize CExtScrollWnd::OnSwGetScrollBarSizes() const
{
	ASSERT_VALID( this );
CSize sizeSb( 0, 0 );
DWORD dwWndStyle = CWnd::GetStyle();
	if( GetScrollBarCtrl(SB_HORZ) == NULL )
	{
		sizeSb.cx = afxData.cxVScroll;
		if( dwWndStyle & WS_BORDER )
			sizeSb.cx -= CX_BORDER;
	} // if( GetScrollBarCtrl(SB_HORZ) == NULL )
	if( GetScrollBarCtrl(SB_VERT) == NULL )
	{
		sizeSb.cy = afxData.cyHScroll;
		if( dwWndStyle & WS_BORDER )
			sizeSb.cy -= CY_BORDER;
	} // if( GetScrollBarCtrl(SB_VERT) == NULL )
	return sizeSb;
}

bool CExtScrollWnd::OnSwCalcClientSizes(
	CSize & size,
	CSize & sizeSb
	)
{
	// return true if enough room to add scrollbars if needed
	ASSERT_VALID( this );
CRect rcClient = OnSwGetClientRect();
	size = rcClient.Size();
	sizeSb = OnSwGetScrollBarSizes();
	if(		sizeSb.cx != 0
		&&	OnSwHasScrollBar( false )
		)
		size.cx += sizeSb.cx;
	if(		sizeSb.cy != 0
		&&	OnSwHasScrollBar( true )
		)
		size.cy += sizeSb.cy;
	return
		( size.cx > sizeSb.cx && size.cy > sizeSb.cy )
			? true : false;
}

bool CExtScrollWnd::OnSwQueryThumbTrackEnabled( bool bHorz ) const
{
	ASSERT_VALID( this );
	bHorz;
	return true;
}

void CExtScrollWnd::OnSwGetScrollBarState(
	CSize sizeClient,
	CSize & sizeNeedSB,
	CSize & sizeRange,
	CPoint & ptMove,
	bool bInsideClient
	) const
{
	ASSERT_VALID( this );
CSize sizeSb = OnSwGetScrollBarSizes();
	sizeRange = OnSwGetTotalSize() - sizeClient;
	ptMove = OnSwGetScrollPos();
bool bNeedH = sizeRange.cx > 0;
	if( !bNeedH )
		ptMove.x = 0;
	else if( bInsideClient )
		sizeRange.cy += sizeSb.cy;
bool bNeedV = sizeRange.cy > 0;
	if( !bNeedV )
		ptMove.y = 0;
	else if ( bInsideClient )
		sizeRange.cx += sizeSb.cx;
	if( bNeedV && (!bNeedH) && sizeRange.cx > 0 )
	{
		ASSERT( bInsideClient );
		bNeedH = true;
		sizeRange.cy += sizeSb.cy;
	} // if( bNeedV && (!bNeedH) && sizeRange.cx > 0 )
	if( sizeRange.cx > 0 && ptMove.x >= sizeRange.cx )
		ptMove.x = sizeRange.cx;
	if( sizeRange.cy > 0 && ptMove.y >= sizeRange.cy )
		ptMove.y = sizeRange.cy;
	sizeNeedSB.cx = bNeedH;
	sizeNeedSB.cy = bNeedV;
}

void CExtScrollWnd::OnSwUpdateScrollBars()
{
	ASSERT_VALID( this );
	if( m_nUpdateScrollBars > 1 )
		return;
	m_nUpdateScrollBars ++;

	ASSERT( OnSwGetTotalSize().cx >= 0 && OnSwGetTotalSize().cy >= 0 );
CRect rcClient;
bool bCalcClient = true;
CWnd * pParentWnd = GetParent();
	if(		pParentWnd != NULL
		&&	(BOOL)pParentWnd->SendMessage(
				WM_RECALCPARENT,
				0,
				(LPARAM)(LPCRECT)&rcClient
				) != 0
		)
		bCalcClient = false;
CSize sizeClient;
CSize sizeSb;
	if( bCalcClient )
	{
		if( !OnSwCalcClientSizes( sizeClient, sizeSb ) )
		{ // no room for scroll bars
			CRect rcClient2 = OnSwGetClientRect();
			if( rcClient2.Width() > 0 && rcClient2.Height() > 0 )
			{
				OnSwEnableScrollBarCtrl( SB_BOTH, false );
				OnSwRecalcLayout( true );
			}
			m_nUpdateScrollBars --;
			return;
		}
	}
	else
	{ // let parent window determine the "client" rect
		sizeSb = OnSwGetScrollBarSizes();
		sizeClient.cx = rcClient.right - rcClient.left;
		sizeClient.cy = rcClient.bottom - rcClient.top;
	}

	// if enough room to add scrollbars
CSize sizeRange;
CPoint ptMove;
CSize sizeNeedSB;
	OnSwGetScrollBarState(
		sizeClient,
		sizeNeedSB,
		sizeRange,
		ptMove,
		bCalcClient
		);
	if( sizeNeedSB.cx )
		sizeClient.cy -= sizeSb.cy;
	if( sizeNeedSB.cy )
		sizeClient.cx -= sizeSb.cx;

	// scroll window + update
	OnSwSetScrollPos( ptMove );

	// the scrollbar page range
SCROLLINFO _scroll_info;
	::memset( &_scroll_info, 0, sizeof(SCROLLINFO) );
	_scroll_info.cbSize = sizeof(SCROLLINFO);
	_scroll_info.fMask = SIF_PAGE|SIF_RANGE;
	_scroll_info.nMin = 0;
	// update bars
	OnSwEnableScrollBarCtrl( SB_HORZ, sizeNeedSB.cx ? true : false );
	if( sizeNeedSB.cx )
	{
		_scroll_info.nPage = sizeClient.cx;
		_scroll_info.nMax = OnSwGetTotalSize().cx - 1;
		if( ! OnSwScrollInfoAdjust(
				SB_HORZ,
				_scroll_info,
				true
				)
			)
			OnSwSetScrollRange(
				SB_HORZ,
				0,
				sizeRange.cx,
				true
				);
	} // if( sizeNeedSB.cx )
	OnSwEnableScrollBarCtrl( SB_VERT, sizeNeedSB.cy ? true : false );
	if( sizeNeedSB.cy )
	{
		_scroll_info.nPage = sizeClient.cy;
		_scroll_info.nMax = OnSwGetTotalSize().cy - 1;
		if( ! OnSwScrollInfoAdjust(
				SB_VERT,
				_scroll_info,
				true
				)
			)
			OnSwSetScrollRange(
				SB_VERT,
				0,
				sizeRange.cy,
				true
				);
	} // if( sizeNeedSB.cy )
	OnSwRecalcLayout( true );
	m_nUpdateScrollBars --;
}

void CExtScrollWnd::OnSwDoScrollWindow(
	int xAmount,
	int yAmount,
	LPCRECT lpRect, // = NULL
	LPCRECT lpClipRect // = NULL
	)
{
	ASSERT_VALID( this );
	if( m_bScrollPhysical )
		CWnd::ScrollWindow(
			xAmount,
			yAmount,
			lpRect,
			lpClipRect
			);
	if( m_bScrollInvalidate )
		OnSwInvalidate( m_bScrollErase );
	if( m_bScrollUpdateWindow )
		CWnd::UpdateWindow();
}

void CExtScrollWnd::OnSwInvalidate( bool bErase )
{
	ASSERT_VALID( this );
CScrollBar * pScrollBarWndH = GetScrollBarCtrl( SB_HORZ );
CScrollBar * pScrollBarWndV = GetScrollBarCtrl( SB_VERT );
	if(		pScrollBarWndH != NULL
		&&	( pScrollBarWndH->GetStyle() & WS_VISIBLE ) == 0
		)
		pScrollBarWndH = NULL;
	if(		pScrollBarWndV != NULL
		&&	( pScrollBarWndV->GetStyle() & WS_VISIBLE ) == 0
		)
		pScrollBarWndV = NULL;
	if( pScrollBarWndH == NULL && pScrollBarWndV == NULL )
	{
		CWnd::Invalidate( bErase ? TRUE : FALSE );
		return;
	} // if( pScrollBarWndH == NULL && pScrollBarWndV == NULL )
CRect rcClientReal;
	CWnd::GetClientRect( &rcClientReal );
CRgn rgnInvalidate;
	if( !rgnInvalidate.CreateRectRgnIndirect(&rcClientReal) )
	{
		CWnd::Invalidate( bErase ? TRUE : FALSE );
		return;
	}
	if( pScrollBarWndH != NULL )
	{
		CRect rcBar;
		pScrollBarWndH->GetWindowRect( &rcBar );
		CWnd::ScreenToClient( &rcBar );
		CRgn rgnBar;
		if(		(! rgnBar.CreateRectRgnIndirect(&rcBar) )
			||	rgnInvalidate.CombineRgn(
					&rgnInvalidate,
					&rgnBar,
					RGN_DIFF
					) == ERROR
			)
		{
			CWnd::Invalidate( bErase ? TRUE : FALSE );
			return;
		}
	} // if( pScrollBarWndH != NULL )
	if( pScrollBarWndV != NULL )
	{
		CRect rcBar;
		pScrollBarWndV->GetWindowRect( &rcBar );
		CWnd::ScreenToClient( &rcBar );
		CRgn rgnBar;
		if(		(! rgnBar.CreateRectRgnIndirect(&rcBar) )
			||	rgnInvalidate.CombineRgn(
					&rgnInvalidate,
					&rgnBar,
					RGN_DIFF
					) == ERROR
			)
		{
			CWnd::Invalidate( bErase ? TRUE : FALSE );
			return;
		}
	} // if( pScrollBarWndV != NULL )
	CWnd::InvalidateRgn( &rgnInvalidate, bErase ? TRUE : FALSE );
}

void CExtScrollWnd::OnSwDoRedraw()
{
	ASSERT_VALID( this );
	if( m_bRedrawInvalidate )
		OnSwInvalidate( m_bRedrawErase );
	if( m_bRedrawUpdateWindow )
		CWnd::UpdateWindow();
}

void CExtScrollWnd::OnSwPaint( CDC & dc )
{
	ASSERT_VALID( this );
	ASSERT( dc.GetSafeHdc() != NULL );
	dc;
}

/////////////////////////////////////////////////////////////////////////////
// CExtScrollWnd message handlers

void CExtScrollWnd::OnSize(UINT nType, int cx, int cy)
{
	CWnd::OnSize(nType, cx, cy);
	if( nType != SIZE_MINIMIZED )
	{
		OnSwRecalcLayout( true );
		OnSwUpdateScrollBars();
		OnSwDoRedraw();
	}
}

void CExtScrollWnd::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	if(		pScrollBar != NULL
		&&	pScrollBar->SendChildNotifyLastMsg()
		)
		return;
	if( pScrollBar != GetScrollBarCtrl(SB_HORZ) )
		return;
	OnSwDoScroll( MAKEWORD(nSBCode, -1), nPos );
}

void CExtScrollWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	if(		pScrollBar != NULL
		&&	pScrollBar->SendChildNotifyLastMsg()
		)
		return;
	if( pScrollBar != GetScrollBarCtrl(SB_VERT) )
		return;
	OnSwDoScroll( MAKEWORD(-1, nSBCode), nPos );
}

BOOL CExtScrollWnd::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
{
	return
		OnSwDoMouseWheel( fFlags, zDelta, point )
			? true : false;
}

BOOL CExtScrollWnd::OnEraseBkgnd(CDC* pDC) 
{
	if( m_bEatErasing )
		return TRUE;
	return CWnd::OnEraseBkgnd(pDC);
}

void CExtScrollWnd::OnPaint() 
{
bool bSingleBufferPaint = false;
CPaintDC dcPaint( this );
CExtPaintManager::stat_ExcludeChildAreas(
		dcPaint.m_hDC,
		m_hWnd,
		CExtPaintManager::stat_DefExcludeChildAreaCallback
		);
CPoint ptSp = OnSwGetScrollPaintPos();
	if( m_bBufferedPainting )
	{
		CRect rcRealClient;
		CWnd::GetClientRect( &rcRealClient );
		CExtMemoryDC dcCompat( &dcPaint, &rcRealClient );
		ASSERT( dcCompat.GetSafeHdc() != NULL );
		if( dcCompat.GetSafeHdc() != NULL )
		{
			CPoint ptVpOld( dcCompat.SetViewportOrg(-ptSp) );
			OnSwPaint( dcCompat );
			dcCompat.SetViewportOrg( ptVpOld );
		} // if( dcCompat.GetSafeHdc() != NULL )
		else
			bSingleBufferPaint = true;
	} // if( m_bBufferedPainting )
	else
		bSingleBufferPaint = true;
	if( bSingleBufferPaint )
	{
		CPoint ptVpOld( dcPaint.SetViewportOrg(-ptSp) );
		OnSwPaint( dcPaint );
		dcPaint.SetViewportOrg( ptVpOld );
	} // if( bSingleBufferPaint )
}

BOOL CExtScrollWnd::PreTranslateMessage(MSG* pMsg) 
{
	if(		pMsg->message == WM_MOUSEWHEEL
		&&	GetSafeHwnd() != NULL
		&&	::IsWindow( GetSafeHwnd() )
		&&	CExtPopupMenuWnd::TestHoverEnabledFromActiveHWND(
				GetSafeHwnd()
				)
		)
	{
		CPoint point = pMsg->lParam;
		HWND hWnd = ::WindowFromPoint( point );
		if( hWnd != NULL && hWnd == m_hWnd )
		{
			UINT fFlags = LOWORD(pMsg->wParam);
			short zDelta = HIWORD(pMsg->wParam);
			if( OnSwDoMouseWheel( fFlags, zDelta, point ) )
				return TRUE;
		}
	}
	
	return CWnd::PreTranslateMessage(pMsg);
}

void CExtScrollWnd::OnSwEnshurePointAvail( CPoint point )
{
	ASSERT_VALID( this );
	if( GetSafeHwnd() == NULL)
		return;
	if( ! ::IsWindow( GetSafeHwnd() ) )
		return;
	if( ! ( OnSwHasScrollBar(false) || OnSwHasScrollBar(true) ) )
		return;
CRect rcClient;
	CWnd::GetClientRect( &rcClient );
	if( rcClient.PtInRect(point) )
		return;

CPoint ptScrollOrg( OnSwGetScrollPos() );
CPoint ptScroll( ptScrollOrg );
CSize sizeTotal( OnSwGetTotalSize() );

	if( OnSwHasScrollBar(true) )
	{
		if( point.x < 0 )
			ptScroll.x += point.x;
		else if( point.x > rcClient.Width() )
			ptScroll.x += point.x - rcClient.Width();
		if( ptScroll.x < 0 )
			ptScroll.x = 0;
		else if( ptScroll.x > sizeTotal.cx )
			ptScroll.x = sizeTotal.cx;
	} // if( OnSwHasScrollBar(true) )
	if( OnSwHasScrollBar(false) )
	{
		if( point.y < 0 )
			ptScroll.y += point.y;
		else if( point.y > rcClient.Height() )
			ptScroll.y += point.y - rcClient.Height();
		if( ptScroll.y < 0 )
			ptScroll.y = 0;
		else if( ptScroll.y > sizeTotal.cy )
			ptScroll.y = sizeTotal.cy;
	} // if( OnSwHasScrollBar(false) )

	if( ptScrollOrg != ptScroll )
		OnSwSetScrollPos( ptScroll );
}


#endif // (!defined __EXT_MFC_NO_SCROLLWND)